package com.zx.process.impl;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.zx.annotation.ColumnConfig;
import com.zx.annotation.DataConfig;
import com.zx.exception.DataParseException;
import com.zx.process.DataConfigProcess;
import com.zx.util.StringUtils;

/**
 * @Project: dataParse
 * @Title: TextDataConfigProcess
 * @Description: 文本格式数据解析类
 * @author: zhangxue
 * @date: 2017年11月18日下午3:19:15
 * @version v1.0
 */
public class TextDataConfigProcess<T> extends DataConfigProcess<T> {
	
	private static Logger logger = LoggerFactory.getLogger(TextDataConfigProcess.class);
	
	public TextDataConfigProcess(Class<T> clazz) throws DataParseException {
		//获得type注解信息
		DataConfig dataConfig = clazz.getAnnotation(DataConfig.class);
		super.setDataConfig(dataConfig);
		super.setClazz(clazz);
		logger.info("初始化文本格式数据解析器【{}】, 文件配置【{}】", clazz, dataConfig);
		boolean isConfig = checkedFieldsConfig();
		if(!isConfig) {
			throw new DataParseException("模板类"+clazz+"没有对字段进行配置");	
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> parseList(String str) throws DataParseException {
		//开启解析为集合的功能
		if(super.getDataConfig().arrayInterval() == 0) {
			throw new DataParseException("arrayInterval = 0 ，未开启集合解析功能，无法将单行数据解析为集合");
		} else {//解析为对象
			return (List<T>)toList(super.getClazz(), str, super.getDataConfig());
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public T parse(String str) throws DataParseException {
		return (T)toBean(super.getClazz(), str, super.getDataConfig());
	}
	
	@Override
	public List<T> parseList(List<String> lines) throws DataParseException {
		if(lines == null || lines.isEmpty()) {
			throw new DataParseException("数据不能为空");
		}
		//开启解析为集合的功能
		List<T> list = new ArrayList<T>(lines.size());
		for (String str : lines) {
			list.add(this.parse(str));
		}
		return list;
	}
	
	@Override
	public List<List<T>> parseListForArrayInterval(List<String> lines) throws DataParseException {
		if(lines == null || lines.isEmpty()) {
			throw new DataParseException("数据不能为空");
		}
		//开启解析为集合的功能
		List<List<T>> list = new ArrayList<List<T>>(lines.size());
		for (String str : lines) {
			list.add(this.parseList(str));
		}
		return list;
	}
	
	/**
	 * @Title: 解析为对象
	 * @param clazz
	 * @param str
	 * @param dataConfig
	 * @return
	 * @throws DataParseException
	 * @date: 2017年12月17日下午10:57:02
	 */
	private Object toBean(Class<?> clazz, String str, DataConfig dataConfig) throws DataParseException{
		Object newInstance = null;
		try {
			newInstance = clazz.newInstance();//创建一个目标类
		} catch (InstantiationException e) {
			throw new DataParseException(e, "类实例化异常");
		} catch (IllegalAccessException e) {
			throw new DataParseException(e, "无法获取这个类的信息");
		}
		List<String> split = StringUtils.split(str, dataConfig.split());//将一行数据进行分割
		
		if(split == null || split.size() == 0) {//校验数据是否为空
			throw new DataParseException("本行数据为空");
		}
		
		if(!checkedLineDataLength(dataConfig, split.size())) {//校验数据长度
			throw new DataParseException("本行数据长度异常");
		}
		
		Field[] declaredFields = clazz.getDeclaredFields();//获得字段的注解信息
		for (Field field : declaredFields) {
			ColumnConfig columnConfig = field.getAnnotation(ColumnConfig.class);
			if(columnConfig != null) {//该字段有对应的数据注入
				String column = split.get(columnConfig.index());
				// 校验是否可以为空以及校验字符串最大长度
				if(checkedIsNull(columnConfig, column) && checkedMaxLength(columnConfig, column)) {
					try {
						convert(field, columnConfig, column, clazz, newInstance);
					} catch (Exception e) {
						throw new DataParseException(e, "数据格式转换异常");//数据格式转换
					}
				}
			}
		}
		return newInstance;
	}
	
	/**
	 * @Title: 解析为List集合
	 * @param clazz
	 * @param str
	 * @param dataConfig
	 * @return
	 * @throws DataParseException
	 * @date: 2017年12月17日下午10:57:02
	 */
	private List<Object> toList(Class<?> clazz, String str, DataConfig dataConfig) throws DataParseException {
		int arrayInterval = dataConfig.arrayInterval();
		int arrayLength = dataConfig.arrayLength();
		List<Object> res = new ArrayList<Object>();
		
		List<String> split = StringUtils.split(str, dataConfig.split());//将一行数据进行分割
		
		if(split == null || split.size() == 0) {//校验数据是否为空
			throw new DataParseException("本行数据为空");
		}
		
		if(!checkedLineDataLength(dataConfig, split.size())) {//校验数据长度
			throw new DataParseException("本行数据长度异常");
		}
		
		if(arrayLength == 0) {//无限解析下去，直到数组的末尾
			int i = 0;
			www:while(true){
				Object newInstance = null;
				try {
					newInstance = clazz.newInstance();//创建一个目标类
				} catch (InstantiationException e) {
					throw new DataParseException(e, "类实例化异常");
				} catch (IllegalAccessException e) {
					throw new DataParseException(e, "无法获取这个类的信息");
				}
				
				Field[] declaredFields = clazz.getDeclaredFields();//获得字段的注解信息
				for (Field field : declaredFields) {
					ColumnConfig columnConfig = field.getAnnotation(ColumnConfig.class);
					if(columnConfig != null) {//该字段有对应的数据注入
						int index = columnConfig.index() + i * arrayInterval;
						if(split.size() <= index){
							break www;//跳出while循环
						}
						String column = split.get(columnConfig.index() + i * arrayInterval);
						// 校验是否可以为空以及校验字符串最大长度
						if(checkedIsNull(columnConfig, column) && checkedMaxLength(columnConfig, column)) {
							try {
								convert(field, columnConfig, column, clazz, newInstance);
							} catch (Exception e) {
								e.printStackTrace();
								break www;//跳出while循环
							}
						}
					}
				}
				res.add(newInstance);
				i++;
			}
		} else {//指定解析集合的个数
			for (int i = 0; i < arrayLength; i++) {
				Object newInstance = null;
				try {
					newInstance = clazz.newInstance();//创建一个目标类
				} catch (InstantiationException e) {
					throw new DataParseException(e, "类实例化异常");
				} catch (IllegalAccessException e) {
					throw new DataParseException(e, "无法获取这个类的信息");
				}
				
				Field[] declaredFields = clazz.getDeclaredFields();//获得字段的注解信息
				for (Field field : declaredFields) {
					ColumnConfig columnConfig = field.getAnnotation(ColumnConfig.class);
					if(columnConfig != null) {//该字段有对应的数据注入
						String column = split.get(columnConfig.index() + i * arrayInterval);
						// 校验是否可以为空以及校验字符串最大长度
						if(checkedIsNull(columnConfig, column) && checkedMaxLength(columnConfig, column)) {
							try {
								convert(field, columnConfig, column, clazz, newInstance);
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					}
				}
				res.add(newInstance);
			}
		}
		
		return res;
	}
	
	/**
	 * @Title: 类型转换
	 * @param field
	 * @param columnConfig
	 * @param column
	 * @param clazz
	 * @param newInstance
	 * @throws DataParseException
	 * @date: 2017年12月17日下午10:27:11
	 */
	private void convert(Field field, ColumnConfig columnConfig, String column, Class<?> clazz, Object newInstance) throws Exception{
		try {
			String type = field.getType().getName();
			PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), clazz);
			Object data = null;
			if("java.lang.String".equals(type)) {//字符串格式
				data = column;
			} else if("java.lang.Integer".equals(type)){
				data = Integer.parseInt(column);
			} else if("java.lang.Long".equals(type)){
				data = Long.parseLong(column);
			} else if("java.lang.Double".equals(type)){
				data = Double.parseDouble(column);
			} else if("java.lang.Float".equals(type)){
				data = Float.parseFloat(column);
			} else if("java.util.Date".equals(type)){
				String pattern = columnConfig.datePattern();
				SimpleDateFormat sdf = new SimpleDateFormat(pattern);
				data = sdf.parse(column);
			} else {
				throw new DataParseException("不支持这种数据类型");
			}
			propertyDescriptor.getWriteMethod().invoke(newInstance, data);
		} catch (IllegalAccessException e) {
			throw e;
		} catch (IllegalArgumentException e) {
			throw e;
		} catch (InvocationTargetException e) {
			throw e;
		} catch (ParseException e) {
			throw e;
		} catch (IntrospectionException e) {
			throw e;
		}
	}

}
